package za.org.jcicada.comms.impl.inprocess;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import za.org.jcicada.comms.impl.ConnectionBase;
import za.org.jcicada.comms.impl.MessageExecutor;
import za.org.jcicada.comms.messages.CommsMessage;

/**
 * An inprocess implementation of the IConnection interface. It has a
 * reference to a peer connection and thus sending a message is simply
 * a matter of submitting the message to the peer connection's message
 * listener.
 */
public class InProcessConnection extends ConnectionBase {

    private static final Log logger = LogFactory.getLog(InProcessConnection.class);
    private boolean closed = false;
    private InProcessConnection otherConnection;
    
    /**
     * Creates a connection linked with the other one.
     * @param otherConnection
     */
    public InProcessConnection(InProcessConnection otherConnection) {
        connectLocalOnly(otherConnection);
        otherConnection.connectLocalOnly(this);
    }
    
    /**
     * Default constructor should only be used by InProcessConnector.connect
     */
    public InProcessConnection() {
    	// TODO: Make this protected and sort out other tests
    }
 
    @Override
    public void close() throws IOException {
        closeLocalOnly();
        if (this.otherConnection != null) {
            this.otherConnection.closeLocalOnly();
        }
    }
    
    @Override
    public boolean isClosed() {
    	return closed;
    }

    @Override
    public void sendMessage(CommsMessage message) throws IOException {
    	MessageExecutor.getInstance().submit(otherConnection.getListener(), message);
    }
    
    private void closeLocalOnly() {
        closed = true;
        try {
        	if (getListener() != null) {
        		getListener().onClose();
        	}
		} catch (Exception e) {
			logger.error("Error during closing connection", e);
		}
    }
    
    protected InProcessConnection getOtherConnection() {
    	return otherConnection;
    }
    
    /**
     * Connect this in-process queue, but don't notify the remote.
     */
    private void connectLocalOnly(InProcessConnection otherConnection) {
        this.otherConnection = otherConnection;
    }
    
}
